package com.runvp.rest.handler;

import com.alibaba.fastjson.JSONObject;
import com.runvp.common.constant.ConstantRedisKey;
import com.runvp.common.core.redis.RedisCache;
import com.runvp.common.enums.*;
import com.runvp.common.exception.base.BaseException;
import com.runvp.common.model.vo.order.BizOrderOutItemVO;
import com.runvp.common.pay.MainPay;
import com.runvp.common.pay.OrderRefundModel;
import com.runvp.common.util.BigDecimalUtil;
import com.runvp.common.util.ToolUtils;
import com.runvp.common.utils.DateUtils;
import com.runvp.common.utils.Threads;
import com.runvp.service.biz.domain.BizOrder;
import com.runvp.service.biz.domain.BizPayRecord;
import com.runvp.service.biz.handler.WechatPayHandler;
import com.runvp.service.biz.service.IBizOrderService;
import com.runvp.service.biz.service.IBizPayRecordService;
import com.runvp.service.out.OutHandler;
import com.runvp.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;

@Slf4j
@Component
public class PayHandler  {


    @Autowired
    private ISysConfigService configService;
    @Autowired
    private IBizOrderService orderService;
    @Autowired
    private WechatPayHandler wechatPayHandler;
    @Autowired
    private OutHandler outHandler;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IBizPayRecordService bizPayRecordService;
    /**
     * 处理支付完成未确认得订单
     */
    @Async("threadPoolTaskExecutor")
    public void handlePayOrder(){
        log.info("队列中处理支付中订单:::开启队列");
        String orderNo;
        String orderNoKey;
        while (true){
            Object orderNoObj = redisCache.brPopByDb(ConstantRedisKey.ORDER_PAY_LIST);
            if(null == orderNoObj){
                Threads.sleep(1000);
                continue;
            }
            //获取平台默认轮询次数
            long loopCount = ToolUtils.objTOLong(configService.selectConfigByKey("loopCount"));
            if(loopCount == 0){
                //系统默认15次
                loopCount = 15;
            }
            orderNo = ToolUtils.toStr(orderNoObj);
            orderNoKey = ConstantRedisKey.ORDER_LOOP+orderNo;
            long count = ToolUtils.objTOLong(redisCache.incr(orderNoKey,1));
            long nc = (count-1);
            log.info("队列中处理支付中订单:::订单【{}】当前轮回次数【{}】",orderNo,nc);
            if(nc > loopCount){
                //超过轮回次数,放弃轮回
                log.info("队列中处理支付中订单:::订单【{}】超过轮回次数【{}】,放弃轮回",orderNo,loopCount);
                redisCache.deleteObject(orderNoKey);
                continue;
            }
            boolean exeRes = singleExe(orderNo);
            if(exeRes){
                //支付处理成功,清理计数器
                redisCache.deleteObject(orderNoKey);
            }else {
                //如果本次支付状态为失败,放入队列，继续轮回
                redisCache.lPush(ConstantRedisKey.ORDER_PAY_LIST,orderNo,86400);
                log.info("队列中处理支付中订单:::订单【{}】未支付，放入队列继续轮回",orderNo);
            }
        }
    }

    /**
     * 单个执行
     * @param orderNo
     */
    private boolean singleExe(String orderNo){
        try{
            //查询订单信息
            BizOrder order = orderService.selectBizOrderByOrderNo(orderNo);
            if (null == order) {
                log.error("订单【{}】不存在或已完成处理",orderNo);
                Threads.sleep(500);
                return false;
            }
            if(!OrderStatus.GO_ON.getCode().equals(order.getStatus())){
                log.error("订单【{}】不是进行中状态,跳过",orderNo);
                return false;
            }
            //如果支付成功则执行充电指令
            List<BizOrderOutItemVO> items = outHandler.executeOut(order,order.getAmount());
            log.info("本次订单队列充电结果:{}",JSONObject.toJSONString(items));
            //充电失败的执行退款
            for(BizOrderOutItemVO item:items){
                singleRefund(item);
            }
            return true;
        }catch (Exception e){
            log.error("本次订单【{}】队列执行结果异常:{}",orderNo,e.getMessage());
            return false;
        }
    }

    /**
     * 单个退款
     * @param item
     */
    private void singleRefund(BizOrderOutItemVO item){
        String orderNo = item.getOrderNo();
        try{
            if(ToolUtils.toInt(item.getGoodsNum())-ToolUtils.toInt(item.getOutSuccessNum()) > 0){
                BizPayRecord record = bizPayRecordService.selectBizPayRecordByOrderNo(orderNo);
                if(null == record){
                    throw new BaseException("退款失败["+DateUtils.now()+"]:未查询到支付记录");
                }
                //给充电失败的执行退款，先计算需要退款的金额
                BigDecimal refundAmount = BigDecimalUtil.mul(item.getGoodsCalcPrice(),BigDecimalUtil.vf(item.getGoodsNum()));
                OrderRefundModel model = new OrderRefundModel();
                model.setId(record.getPayId());
                model.setRefund_order_no(record.getPayOrderNo());
                model.setRefund_amt(ToolUtils.toStr(refundAmount));
                //执行退款
                JSONObject json = MainPay.refund(model);
                String status = json.getString("status");
                if(!AdapayPayStatus.PENDING.getCode().equals(status)) {
                    throw new BaseException("退款失败["+ DateUtils.now()+"]:"+AdapayPayStatus.getDesc(status));
                }
                //查询退款状态
                JSONObject res = checkRefundStatus(model);
                if (res == null) {
                    throw new BaseException("退款失败[" + DateUtils.now() + "]:未查询到退款结果");
                }
                json.put("reqUrl", "MainPay.refund");
                json.put("orderNo", orderNo);
                json.put("createBy", record.getCreateBy());
                json.put("payType", PayChannel.PAY_WECHAT.getCode());
                json.put("tranType", TranType.RECOVERY_IN.getCode());
                JSONObject refunds = res.getJSONArray("refunds").getJSONObject(0);
                json.put("id", refunds.getString("refund_id"));
                json.put("pay_amt", refunds.getString("refund_amt"));
                json.put("order_no", refunds.getString("refund_order_no"));
                bizPayRecordService.savePayRecord(json);
                log.info("退款成功信息:{}",res.toJSONString());
            }
        }catch (Exception e){
            log.error("订单【{}】退款失败:{}",orderNo,e.getMessage());
        }

    }
    /**
     * 查询退款状态
     * @param model
     * @return boolean
     */
    private JSONObject checkRefundStatus(OrderRefundModel model){
        JSONObject res ;
        for (int i = 0; i < 5; i++) {
            res = MainPay.refundQuery(model);
            if(AdapayPayStatus.PAY_SUCCEEDED.getCode().equals(res.getString("status"))){
                return res;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
            }
        }
        return null;
    }

    /**
     * 是否是三方支付
     * @param orderNo
     * @return boolean true:是
     */
    private boolean isAdaPay(String orderNo){
        if(orderNo.startsWith(PayPlat.PAY_QR_ALIPAY.getCode())
                || orderNo.startsWith(PayPlat.PAY_QR_WECHAT.getCode())
                ||orderNo.startsWith(PayChannel.PAY_WECHAT.getCode())
                || orderNo.startsWith(PayChannel.PAY_ALIPAY.getCode())){
            return true;
        }
        return false;
    }
    /**
     * 查询支付结果
     * @param order
     * @return JSONObject
     */
    public JSONObject checkPayResult(BizOrder order){
        JSONObject payStatus ;
        String orderNo = order.getOrderNo();
        if(PayChannel.PAY_CLOUD_CARD.getCode().equals(order.getType())){
            payStatus = new JSONObject();
            payStatus.put("status","succeeded");
            payStatus.put("pay_amt", order.getAmount());
            return payStatus;
        }
        if(orderNo.startsWith(OrderPayMethod.PAY_QR_WECHAT.getCode())){
            payStatus = wechatPayHandler.getWechatPayStatus(orderNo);
        }else {
            payStatus = wechatPayHandler.getPayStatus(orderNo);
        }
        //pending :交易处理中,succeeded :交易成功,failed :交易失败
        String status = payStatus.getString("status");
        if(!"succeeded".equals(status)){
//            if("failed".equals(status)){
////                throw new BaseException("订单【" + orderNo + "】未完成支付:"+payStatus.getString("error_msg"));
//            }
            throw new BaseException("订单未完成支付");
        }
        return payStatus;
    }
    /**
     * 支付回调处理
     *
     * @param orderNo
     * @return
     */
    public synchronized Object payCallback(String orderNo) {
        List<BizOrderOutItemVO> items;
        //查询订单信息
        BizOrder order = orderService.selectBizOrderByOrderNo(orderNo);
        if (null == order) {
            throw new BaseException("订单【" + orderNo + "】不存在");
        }
        //支付状态
        JSONObject payStatus = checkPayResult(order);
        items = outHandler.executeOut(order,payStatus.getBigDecimal("pay_amt"));
        if(DeviceType.WECHAT.getCode().equals(order.getDeviceType())){
            //小程序售货机充电失败的执行退款
            for(BizOrderOutItemVO item:items){
                singleRefund(item);
            }
        }
        return items;
    }



}
